package my.mark.mybaibaoxiang.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileInputStream;
import java.io.IOException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * @Description: 
 * md5Util 
 * @Author wxming
 * @Date 2019年10月31日 下午12:59:14
 */
public class MD5Util {
    private static final Logger LOG = LoggerFactory.getLogger(MD5Util.class);

    public final static String MD5(String pwd) {
        try {
            //使用平台的默认字符集将此 String 编码为 byte序列，并将结果存储到一个新的 byte数组中
            byte[] btInput = pwd.getBytes();

            // 获得指定摘要算法的 MessageDigest对象，此处为MD5
            //MessageDigest类为应用程序提供信息摘要算法的功能，如 MD5 或 SHA 算法。
            //信息摘要是安全的单向哈希函数，它接收任意大小的数据，并输出固定长度的哈希值。 
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            //System.out.println(mdInst);  
            //MD5 Message Digest from SUN, <initialized>

            //MessageDigest对象通过使用 update方法处理数据， 使用指定的byte数组更新摘要
            mdInst.update(btInput);
            //System.out.println(mdInst);  
            //MD5 Message Digest from SUN, <in progress>

            // 摘要更新之后，通过调用digest（）执行哈希计算，获得密文
            byte[] md = mdInst.digest();
            //System.out.println(md);

            // 把密文转换成十六进制的字符串形式
            return byteArrayToHex(md);

        } catch (Exception e) {
            LOG.error("", e);
            return null;
        }
    }

    public static String fileMD5(String inputFile) throws IOException {
        // 缓冲区大小（这个可以抽出一个参数）
        int bufferSize = 256 * 1024;
        FileInputStream fileInputStream = null;
        DigestInputStream digestInputStream = null;
        try {
            // 拿到一个MD5转换器（同样，这里可以换成SHA1）
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            // 使用DigestInputStream
            fileInputStream = new FileInputStream(inputFile);
            digestInputStream = new DigestInputStream(fileInputStream, messageDigest);
            // read的过程中进行MD5处理，直到读完文件
            byte[] buffer = new byte[bufferSize];
            while (digestInputStream.read(buffer) > 0);
            // 获取最终的MessageDigest
            messageDigest = digestInputStream.getMessageDigest();
            // 拿到结果，也是字节数组，包含16个元素
            byte[] resultByteArray = messageDigest.digest();
            // 同样，把字节数组转换成字符串
            return byteArrayToHex(resultByteArray);
        } catch (NoSuchAlgorithmException e) {
            LOG.error("", e);
            return null;
        } finally {
            try {
                digestInputStream.close();
            } catch (Exception e) {
                LOG.error("", e);
                return null;
            }
            try {
                fileInputStream.close();
            } catch (Exception e) {
                LOG.error("", e);
                return null;
            }
        }
    }

    public static String byteArrayToHex(byte[] byteArray) {
        //用于加密的字符
        char md5String[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
                            'E', 'F' };

        int j = byteArray.length;
        //System.out.println(j);
        char str[] = new char[j * 2];
        int k = 0;
        for (int i = 0; i < j; i++) { //  i = 0
            byte byte0 = byteArray[i]; //95
            str[k++] = md5String[byte0 >>> 4 & 0xf]; //    5  
            str[k++] = md5String[byte0 & 0xf]; //   F
        }

        //返回经过加密后的字符串
        return new String(str);
    }
    
}
